/**
 * Copyright (C) 2009 All Rights Reserved
 * @author sebastian chang
 * @brief practice
 */

#ifndef _TEST_THREAD_QUEUE_H_
#define _TEST_THREAD_QUEUE_H_

#include <iostream>
using namespace std;

#include <pthread.h>
#include <errno.h>

#include "thread_queue.h"
#include "thread_event.h"

using namespace trident;

struct thread_task_t
{
    thread_task_t(int index_ = 0) : index(index_)
    {
        
    }

    int index;
    string content;
};

class thread_management_t
{
public:
    typedef void* (*thread_function_t)(void*);

public:
    bool start()
    {
        bool ret = true;

        _producer_thread_working = true;
        if (!startThread(_producer_pthread_id, producerThreadFunction) )
        {
            // TODO
        }

        _consumer_thread_working = true;
        if (!startThread(_consumer_pthread_id, consumerThreadFunction) )
        {
            // TODO
        }

        return ret;
    }

    bool stop()
    {
        bool ret = true;

        _producer_thread_working = false;
        _producer_thread_event.setEvent();

        _consumer_thread_working = false;
        // TODO push thread exit task

        return ret;
    }

    bool initialize()
    {
        _producer_thread_event.init();

        _thread_queue.init();

        return true;
    }

private:

    bool startThread(pthread_t pthread_id_, thread_function_t thread_function_)
    {
        bool ret = false;

        pthread_attr_t pthread_attr;
        if (0 == pthread_attr_init(&pthread_attr) )
        {
            pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED);
            if (0 == pthread_create(&pthread_id_, &pthread_attr, thread_function_, this) )
            {
                ret = true;
            }
        }

        pthread_attr_destroy(&pthread_attr);

        return ret;
    }

    static void* producerThreadFunction(void* args_)
    {
        thread_management_t* thread_management = static_cast<thread_management_t*>(args_);

        thread_management->producerThread();

        return (void*)0;
    }

    void producerThread()
    {
        unsigned long timeout = 1000 * 2; // 10 seconds
        thread_task_t* thread_task = NULL;
        int index = 0;
        int ret = 0;

        while (_producer_thread_working)
        {
            switch(ret = _producer_thread_event.waitEvent(timeout))
            {
            case 0:
                break;
            case ETIMEDOUT:
                thread_task = new thread_task_t(++index);
                _thread_queue.push(thread_task, false);
                break;
            default:
                break;
            }
        }
    }

    static void* consumerThreadFunction(void* args_)
    {
        thread_management_t* thread_management = static_cast<thread_management_t*>(args_);

        thread_management->consumerThread();

        return (void*)0;
    }

    void consumerThread()
    {
        unsigned long timeout = 1000 * 4; // 1 seconds
        thread_task_t* thread_task;
        int ret = 0;

        while (_consumer_thread_working)
        {
            switch(ret = _thread_queue.pop(thread_task, timeout))
            {
            case 0:
                // TODO use log system
                if (NULL != thread_task)
                {
                    delete thread_task;
                    thread_task = NULL;
                }
                break;
            case ETIMEDOUT:
                break;
            default:
                break;
            }
        }
    }

private:

    pthread_t                           _producer_pthread_id;
    pthread_t                           _consumer_pthread_id;

    thread_event_t                      _producer_thread_event;

    bool                                _producer_thread_working;
    bool                                _consumer_thread_working;

    thread_queue_t<thread_task_t*>      _thread_queue;
};



int test_thread_queue()
{
    cout<<"Test thread queue lib"<<endl;

    thread_management_t thread_management;
    thread_management.initialize();
    thread_management.start();

    sleep(60);

    thread_management.stop();

    return 0;
}

#endif //_TEST_THREAD_QUEUE_H_

